Technical Q&A QA1298
Resolves may return an IPv6 address in Panther


Q: Mac OS X 10.3 になってから、Resolve コールバック関数が IP アドレスが 0.0.0.0 である sockaddr を返すことがあります。どうなっているのでしょう。

A: Rendezvous は Mac OS X 10.3 以降において IPv6 アドレスレコードをサポートしています。したがって、この 0.0.0.0 アドレスは、実際にはおそらく IPv6 である sockaddr を IPv4 として解析した結果です。アドバタイズされる自分のサービスが IPv6 をサポートしない場合もあるので、おそらくすべての IPv6 アドレスを無視することになるでしょう。以下は、CFNetServices と NSNetServices の両サービスで IPv6 アドレスを無視する方法を示すコードです。



リスト 1. CFNetServices Resolve コールバック関数の例

static void
MyResolveCallback(CFNetServiceRef service, CFStreamError* error, void* info)
{
struct sockaddr * socketAddress;
CFArrayRef addresses;
char buffer[256];
uint16_t port;
int newIP;

addresses = CFNetServiceGetAddressing(service);
newIP = CFArrayGetCount(addresses) - 1;

/* <netinet/in.h> と <arpa/inet.h> を必ずインクルードする */
    
socketAddress = (struct sockaddr *)
CFDataGetBytePtr(CFArrayGetValueAtIndex(addresses, newIP));

/* アドレスが IPv4 アドレスの場合にのみ続行する */
if (socketAddress && socketAddress->sa_family == AF_INET)
  {
if (inet_ntop(AF_INET, &((struct sockaddr_in *)
socketAddress)->sin_addr, buffer, sizeof(buffer))) {
        
port = ntohs(((struct sockaddr_in *)socketAddress)->sin_port);

printf("IP Address = %s¥n", buffer);
printf("Port Number = %d¥n", port);
        
/* IP アドレスとポート番号がわかったので、サービスへの接続を試みる。
   接続に成功したら、Resolve 操作を取り消す。接続に失敗したら、
   Resolve コールバックが別の IPv4 アドレスを使用して再度呼び出される
   場合に備えて Resolve を実行状態に保ち、次に新規アドレスへの接続を試みる。*/
    }
  }

return;
}




リスト 2. NSNetServices netServiceDidResolveAddress メソッドの例

- (void)netServiceDidResolveAddress:(NSNetService *)sender {
  
NSData * address;
struct sockaddr * socketAddress;
char buffer[256];
int newIP;

newIP = [[sender addresses] count] - 1;
address = [[sender addresses] objectAtIndex:newIP];

/* <netinet/in.h> と <arpa/inet.h> を必ずインクルードする */

socketAddress = (struct sockaddr *)[address bytes];

/* アドレスが IPv4 アドレスの場合にのみ続行する */
if (socketAddress && socketAddress->sa_family == AF_INET)
  {
if (inet_ntop(AF_INET, &((struct sockaddr_in *)
socketAddress)->sin_addr, buffer, sizeof(buffer))) {
          
ntohs(((struct sockaddr_in *)socketAddress)->sin_port)];
          
printf("IP Address = %s¥n", buffer);
printf("Port Number = %d¥n", port);
        
/* IP アドレスとポート番号がわかったので、サービスへの接続を試みる。
   接続に成功したら、Resolve 操作を取り消す。接続に失敗したら、
   Resolve コールバックが別の IPv4 アドレスを使用して再度呼び出される
   場合に備えて Resolve を実行状態に保ち、次に新規アドレスへの接続を試みる。*/
  }
  
return;
}



[2003 年 10 月 15 日]